#pragma once

#include<iostream>
#include<unistd.h>
#include<cstring>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"nocopy.hpp"
static const int gsockfd = -1;
static const uint16_t glocalport = -1;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
};

class UdpServer : public nocopy
{
public:
    UdpServer(uint16_t localport = glocalport)
        :_sockfd(gsockfd)
        ,_localport(localport)
        ,_isrunning(false)
    {

    }
    void InitServer()
    {
        //创建socket文件
        _sockfd = ::socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd < 0)
        {
            std::cout << "socket error" << std::endl;
            exit(SOCKET_ERROR);
        }
        std::cout << "socket create success,_socket:" << _sockfd << std::endl;
        //bind
        struct sockaddr_in local;
        memset(&local,0,sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(_localport);
        local.sin_addr.s_addr = INADDR_ANY;

        int n = ::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n < 0)
        {
            std::cout << "bind error" << std::endl;
            exit(BIND_ERROR);
        }
        std::cout << "bind success" << std::endl;
    }
    void Start()
    {
        _isrunning = true;
        char inbuffer[1024];
        while(_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_sockfd,inbuffer,sizeof(inbuffer) - 1,0,(struct sockaddr*)&peer,&len);
            if(n > 0)
            {
                std::string peerip = inet_ntoa(peer.sin_addr);
                uint16_t peerport = ntohs(peer.sin_port);
                std::cout << "[" << peerip << " " << peerport << "]# " << inbuffer << std::endl;

                inbuffer[n] = 0;
                std::string echo_string = "udp_server echo# ";
                echo_string += inbuffer;

                sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)&peer,len);
            }
        }
    }
    ~UdpServer()
    {
        if(_sockfd > gsockfd) close(_sockfd);
    }
private:
    int _sockfd;
    uint16_t _localport;
    bool _isrunning;
};